// CS 362
// Tim Chen

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "dominion.h"
#include "dominion_helpers.h"
#include "rngs.h"

#define NOISY_TEST 1

// Note: Dominion has 500 cards, 50% of the time should be kingdom.  25% treasure.  25% victory/curse.

void makeRandomDeck(struct gameState *state, int *k, int player){
	int a;
	int randCardType, randKingdomType, randTreasureType, randVictoryType;
	// Build deck with random cards
	for(a = 0; a < state->deckCount[player]; a++){
		randCardType = rand() % 4;
		if(randCardType == 1){ // let 1 represent treasure card
			randTreasureType = rand() % 3; // 3 different types of treasure cards
			if(randTreasureType == 0){ // let 0 represent silver
				state->deck[player][a] = silver;
			}else if(randTreasureType == 1){ // let 1 represent gold
				state->deck[player][a] = gold;
			}else{ // let 2 & all other cases represent copper
				state->deck[player][a] = copper;
			}
		}else if(randCardType == 2){ // let 2 represent victory & curse cards
			randVictoryType = rand() % 4; // 3 victory type & curses
			if(randVictoryType == 0){ // let 0 be curses
				state->deck[player][a] = curse;
			}else if(randVictoryType == 1){ // let 1 be duchy
				state->deck[player][a] = duchy;
			}else if(randVictoryType == 2){ // let 2 be province
				state->deck[player][a] = province;
			}else{ // let all other cases be estate
				state->deck[player][a] = estate;
			}
		}else{ // all other types should be kingdom cards
			randKingdomType = rand() % 10;
			state->deck[player][a] = k[randKingdomType];
		}
	}
}

void makeRandomHand(struct gameState *state, int *k, int player){
	int a;
	int randCardType, randKingdomType, randTreasureType, randVictoryType;
	// Build deck with random cards
	for(a = 0; a < state->handCount[player]; a++){
		randCardType = rand() % 4;
		if(randCardType == 1){ // let 1 represent treasure card
			randTreasureType = rand() % 3; // 3 different types of treasure cards
			if(randTreasureType == 0){ // let 0 represent silver
				state->hand[player][a] = silver;
			}else if(randTreasureType == 1){ // let 1 represent gold
				state->hand[player][a] = gold;
			}else{ // let 2 & all other cases represent copper
				state->hand[player][a] = copper;
			}
		}else if(randCardType == 2){ // let 2 represent victory & curse cards
			randVictoryType = rand() % 4; // 3 victory type & curses
			if(randVictoryType == 0){ // let 0 be curses
				state->hand[player][a] = curse;
			}else if(randVictoryType == 1){ // let 1 be duchy
				state->hand[player][a] = duchy;
			}else if(randVictoryType == 2){ // let 2 be province
				state->hand[player][a] = province;
			}else{ // let all other cases be estate
				state->hand[player][a] = estate;
			}
		}else{ // all other types should be kingdom cards
			randKingdomType = rand() % 10;
			state->hand[player][a] = k[randKingdomType];
		}
	}
}

void makeRandomDiscard(struct gameState *state, int *k, int player){
	int a;
	int randCardType, randKingdomType, randTreasureType, randVictoryType;
	// Build deck with random cards
	for(a = 0; a < state->discardCount[player]; a++){
		randCardType = rand() % 4;
		if(randCardType == 1){ // let 1 represent treasure card
			randTreasureType = rand() % 3; // 3 different types of treasure cards
			if(randTreasureType == 0){ // let 0 represent silver
				state->discard[player][a] = silver;
			}else if(randTreasureType == 1){ // let 1 represent gold
				state->discard[player][a] = gold;
			}else{ // let 2 & all other cases represent copper
				state->discard[player][a] = copper;
			}
		}else if(randCardType == 2){ // let 2 represent victory & curse cards
			randVictoryType = rand() % 4; // 3 victory type & curses
			if(randVictoryType == 0){ // let 0 be curses
				state->discard[player][a] = curse;
			}else if(randVictoryType == 1){ // let 1 be duchy
				state->discard[player][a] = duchy;
			}else if(randVictoryType == 2){ // let 2 be province
				state->discard[player][a] = province;
			}else{ // let all other cases be estate
				state->discard[player][a] = estate;
			}
		}else{ // all other types should be kingdom cards
			randKingdomType = rand() % 10;
			state->discard[player][a] = k[randKingdomType];
		}
	}
}

// Written by Tim Chen
void testAdventurer(){
	int player, preHandCount, handCount;
	int preDeckCount, deckCount;
	int prePlayedCount, playedCount;
	int preDiscardCount, discardCount;
	int preMoneyCount, moneyCount;
	int seed; // = 50;
	int numPlayer = 3;
	struct gameState state;
	int cur, it, jt, i, t;
	int k[10] = {adventurer, council_room, feast, gardens, mine,
					remodel, smithy, village, baron, great_hall};
	int preCopper, postCopper;
	int preSilver, postSilver;
	int preGold, postGold;


	// set choices to playDom example
	int choice1 = 0, choice2 = 0, choice3 = 0, handPos = 0, bonus=0;

	// randomize seed
	seed = rand() % 50;

	// Randomly test this 50 times at some point?
	//for(player = 0; player < numPlayer; player++){
	for(t = 0; t < 50; t++){
		printf("BEGIN ADVENTURER TEST #%d\n", t);
		// initialize game
		preMoneyCount = 0;
		moneyCount = 0;
		preCopper = 0, postCopper = 0;
		preSilver = 0, postSilver = 0;
		preGold = 0, postGold = 0;

	   	int r = initializeGame(numPlayer, k, seed, &state);
		if(r < 0){
	    	printf("Error initializing game...\n");
		}

		// set the RANDOM player
		player = rand() % numPlayer; // randomize the player
		state.whoseTurn = player;
		printf("Selected Player: %d\n", player);
		
		// set the deck count
		state.deckCount[player] = 20;
		makeRandomDeck(&state, k, player);

		//state.handCount[player] = 5; // ensure 5 default
		makeRandomHand(&state, k, player);

		state.discardCount[player] = rand() % 10; // set a random # of discards within 10
		makeRandomDiscard(&state, k, player);


	#if (NOISY_TEST == 1)
		//printf("Verifying random deck...\n");
		//printf("Card 1: %d, Card 2: %d, Card 3: %d, Card 4: %d, Card 5: %d\n", state.deck[player][0], state.deck[player][1], state.deck[player][2], state.deck[player][3], state.deck[player][4], state.deck[player][5]);
	#endif 

		// compensate for initializeGame where other players don't draw their cards
		if(player > 0){
			for(it = 0; it < 5; it++){
                 drawCard(state.whoseTurn, &state);
			}
		}

		// update money count for current player
		for(jt = 0; jt < state.handCount[0]; jt++){
			if(state.hand[0][jt] == copper){ // copper
				preMoneyCount++;
				preCopper++;
			}else if(state.hand[0][jt] == silver){ //silver
				preMoneyCount += 2;
				preSilver++;
			}else if(state.hand[0][jt] == gold){ // gold
				preMoneyCount += 3;
				preGold++;
			}
		}

	#if (NOISY_TEST == 1)
		printf("Player %d Money Count so far: %d. Copper: %d, Silver: %d, Gold: %d\n", player, preMoneyCount, preCopper, preSilver, preGold);
	#endif

		// verify empty hand
		if(state.handCount[player] == 0){
	         state.handCount[player] = 1;
	#if (NOISY_TEST == 1)
			printf("Player %d handcount was empty, new handcount: %d\n", player, state.handCount[player]);
	#endif
		}

		// force adventurer card to be the first card in hand
		state.hand[player][0] = adventurer;		

		// Determine preconditions
		preHandCount = state.handCount[player];
		preDeckCount = state.deckCount[player];
		prePlayedCount = state.playedCardCount; // discard pile
		preDiscardCount = state.discardCount[player]; // different type of discard

	#if (NOISY_TEST == 1)
		//printf("Verifying current hand...\n");
		//printf("Card 1: %d, Card 2: %d, Card 3: %d, Card 4: %d, Card 5: %d\n", state.hand[player][0], state.hand[player][1], state.hand[player][2], state.hand[player][3], state.hand[player][4], state.hand[player][5]);
	#endif

		cur = cardEffect(adventurer, choice1, choice2, choice3, &state, handPos, &bonus);
	    if(cur != 0){
	        printf("ERROR: Adventurer card could not be used.\n");
			break;
		}                                                        
		// obtain postconditions
		handCount = state.handCount[player];
		deckCount = state.deckCount[player];
		playedCount = state.playedCardCount;
		discardCount = state.discardCount[player];

			
		// Adventurer Card will lose 2 cards from deck to hand and any # of discards.
	#if (NOISY_TEST == 1)
	    printf("Player %d Deck Count - Before: %d After: %d\n", player, preDeckCount, deckCount);
		printf("Player %d Discard Count - Before: %d After: %d\n", player, preDiscardCount, discardCount);
		printf("Player %d Deck Sanity - Expected %d Actual: %d\n", player, preDeckCount, deckCount + discardCount + 2);
	#endif
		//assert(deckCount + 2 + discardCount == preDeckCount);

	#if (NOISY_TEST == 1)
		// Adventurer Card should add 2 more cards to the hand
        printf("Player %d Hand Count - Before: %d Expected: %d  Actual: %d\n", player, preHandCount, preHandCount + 2, handCount);
	#endif
		//assert(preHandCount + 2 == handCount);

		// Calculate post money
		for(i = 0; i < state.handCount[0]; i++){
			if(state.hand[0][i] == copper){ // copper
				moneyCount++;
				postCopper++;
			}else if(state.hand[0][i] == silver){ //silver
				moneyCount += 2;
				postSilver++;
			}else if(state.hand[0][i] == gold){ // gold
				moneyCount += 3;
				postGold++;
			}
		}

	#if (NOISY_TEST == 1)
		printf("Player %d Money Count Now: %d. Copper: %d, Silver: %d, Gold: %d\n", player, moneyCount, postCopper, postSilver, postGold);
		printf("Player %d Pre$$: %d, Post$$: %d\n", player, preMoneyCount, moneyCount);
	#endif
		assert(moneyCount >= preMoneyCount);


	}
	printf("Finishing testAdventurer()\n");
}

int main(){
	testAdventurer();
	return 0;
}
